<template lang="pug">
div(v-clickoutside="close()")
  .ui.input.fluid
    input(
      v-if="isValid(unix)",
      type="text",
      v-model="date",
      @click="open",
    )
    input(
      v-else,
      type="text",
      :value="unix ? '无效的时间' : (placeholder || '未设置')",
      @click="open",
    )
  .flex.dc(style="z-index:1; background: white; position: absolute; width: 300px; border: 1px solid #ccc; padding: 5px;", v-if="show")
    .flex.ac.jsb
      .month(@click="m = m.subtract(1, 'month')") <
      a.pointer(style="white-space: nowrap; padding: 0 10px;", @click="backToday", v-if="m.toString() !== now.toString()") 回今天
      div
        .flex.ac.jc
          .ui.input
            input(
              type="number",
              min="1970",
              max="2999",
              v-model="year",
              style="width: 75px;",
            )
          .ui.input
            input(
              type="number",
              :min="1",
              :max="12",
              v-model="month",
              style="width: 58px;",
            )
          //- .ui.input
          //-   input(
          //-     type="number",
          //-     :min="1",
          //-     :max="30",
          //-     v-model="day",
          //-   )
      a.pointer(style="white-space: nowrap; padding: 0 10px;", @click="setNull") 清空
      .month(@click="m = m.add(1, 'month')") >
    .flex.ac.jsb(style="margin: 5px 0;")
      .weekday 一
      .weekday 二
      .weekday 三
      .weekday 四
      .weekday 五
      .weekday 六
      .weekday 日
    template(v-for="weekdays in computedDays")
      .flex.ac.jsb
        .day(
          v-for="day in weekdays",
          :class="{'not-current-month': day.month() !== month-1, chosen: day.toString() === m.toString()}"
          @click="setDay(day)",
        ) {{day.date()}}
    template(v-if="type !== 'date'")
      .ui.divider
      template(v-for="time in times")
        .flex.ac.jsb
          div(
            v-for="hour in time",
            :class="{time: !_.isNumber(hour), 'time-placeholder': _.isNumber(hour), chosen: hour.toString() === m.toString()}",
            @click="setTime(hour)",
          ) {{_.isNumber(hour) ? '' : hour.format('HH:mm')}}
</template>

<script>
export default {
  name: 'date',
  props: ['unix', 'placeholder', 'type'],
  data () {
    return {
      show: false,
      showLock: false,
    }
  },
  methods: {
    setNull() {
      this.unix = null
      this.show = false
    },
    backToday(){
      this.showLock = true
      this.m = this.now
    },
    close(){
      if (this.showLock) {
        this.showLock = false
      } else {
        this.show = false
      }
    },
    setDay (day) {
      this.m = day
      this.showLock = true
    },
    setTime (time) {
      this.m = time
      this.showLock = true
    },
    isValid(val) {
      const m = _.isNumber(val) ? moment.unix(val) : moment(val)
      return val && m.isValid()
    },
    open (){
      this.showLock = true
      if (!this.isValid(this.unix)) {
        this.unix = moment().unix()
      }
      this.show = true
    },
  },
  ready () {
  },
  computed: {
    now() {
      return moment().set({second:0, millisecond:0})
    },
    times () {
      const hours = _(0)
      .range(24)
      .map(i=>{
        return moment(this.m).hour(i).minute(0).second(0).millisecond(0)
      })
      .value()
      const suffix = _(5-hours.length%5)
      .range()
      .value()
      return _.chunk(_.concat(hours, suffix), 5)
    },
    computedDays() {
      const prefix = _(this.lastMonthDays-this.weekday+2)
      .range(this.lastMonthDays+1)
      .map(i=>{
        return moment(this.m).subtract(1, 'month').date(i)
      })
      .value()
      const suffix = _(1)
      .range(8-this.lastWeekday)
      .map(i=>{
        return moment(this.m).add(1, 'month').date(i)
      })
      .value()
      const current = _(1)
      .range(this.days+1)
      .map(i=>{
        return moment(this.m).date(i)
      })
      .value()
      return _.chunk(_.concat(prefix, current, suffix), 7)
    },
    lastMonthDays () {
      return moment(this.m).date(1).subtract(1, 'day').date()
    },
    days () {
      return moment(this.m).date(1).add(1, 'month').subtract(1, 'day').date()
    },
    weekday () {
      const result = moment(this.m).date(1).day()
      return result ? result : 7
    },
    lastWeekday () {
      const result = moment(this.m).date(this.days).day()
      return result ? result : 7
    },
    m: {
      get () {
        return moment.unix(this.unix).set(_.assign({second:0, millisecond:0}, this.type!=='date'?{}:{hour: 0}))
      },
      set (v) {
        this.unix = moment(v).set(_.assign({second:0, millisecond:0}, this.type!=='date'?{}:{hour: 0})).unix()
      }
    },
    date: {
      get () {
        return this.m.format(this.type !== 'date' ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD')
      },
      set (v) {
        if (this.isValid(v)) {
          this.m = moment(v, this.type !== 'date' ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD')
        }
      }
    },
    year: {
      get () {
        return this.m.year()
      },
      set (v) {
        this.m = this.m.year(v)
      }
    },
    month: {
      get () {
        return this.m.month() + 1
      },
      set (v) {
        this.m = this.m.month(v-1)
      }
    },
    day: {
      get () {
        return this.m.date()
      },
      set (v) {
        this.m = this.m.date(v)
      }
    },
  },
}
</script>

<style lang="sass" scoped>
.weekday, .day, .month, .time, .time-placeholder
  width: 100%
  text-align: center
.day, .month, .time
  cursor: pointer
.day, .time, .time-placeholder
  padding: 10px
.day:hover, .time:hover, .chosen
  background-color: #eee
.not-current-month
  color: #afafaf
// TODO: 禁用和可用日期时间
.disabled
  cursor: not-allowed
  color: #cecece
.disabled:hover
  background-color: #fff
</style>
